//@author A0121105E

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.JTextComponent;

public class PopUps {

	private static JDialog jd;
	private static JLabel taskIDLabel, nameLabel, startTimeLabel, endTimeLabel,
			locationLabel, dateLabel, tagLabel, descriptionLabel, tableLabel;
	private static JTextField nameField, startTimeField, endTimeField,
			locationField, dateField, tagField;
	private static JPanel basicPanel, taskIDPanel, namePanel, timePanel,
			datePanel, locationTagPanel, descriptionPanel, buttonPanel,
			tablePanel;
	private static JTextArea descriptionText;
	private static JButton saveButton;
	private static Task task;
	private static boolean isSearch = false;
	private static boolean isSyntaxError = false;
	private static boolean isComplete = false;
	private static boolean isTagErrorFound = false;
	private static boolean isAdd = false;
	private static boolean isEdit = false;
	
	private static String[] tableColumns = { "ID", "Start", "End", "Project", "Name", "Done" };
	private static String[] taskUITags = { "/id", "/st", "/et", "/pl", "/des", "/key", "/tit", "-d", "-nd" };
	private static final String PROJECT_TAG = "#";

	
	private static JTable myTable;
	private static DefaultTableModel myTableModel;
	private static JScrollPane scrollPane;
	private static JCheckBox doneCheckBox;
	
	private static ArrayList<JTextField> textFieldsList;
	private static ArrayList<String> taskTextFields;
	
	private static SimpleDateFormat sdf1 = new SimpleDateFormat("dd/MM/yyyy HH:mm");
	private static SimpleDateFormat sdf2 = new SimpleDateFormat("dd/MM/yyyy");
	
	private static final String MSG_STORAGE_CHAR_ERROR = "The character \"`\" is not allowed.";
	private static final String MSG_NO_TITLE_ERROR = "Title cannot be empty";
	private static final String dateOrderError = "End Time should come after Start Time";
	private static final String DATE_TIME_FORMAT = "dd/MM/yyyy HH:mm";
	private static final String DATE_ONLY_FORMAT = "dd/MM/yyyy";
	private static final String WRONG_DATE_FORMAT = "The date format is wrong. Please enter again.";
	private static final String MESSAGE_WRONG_DATE_FORMAT = "\"%1$s\" is not in the right date-time format.\nPlease use "
			+ DATE_TIME_FORMAT + " or " + DATE_ONLY_FORMAT;
	private static final String WRONG_ST_FORMAT = "System cannot understand Start Time Format.";
	private static final String WRONG_ET_FORMAT = "System cannot understand End Time Format.";
	private static final String MSG_TAG_NOT_ALLOWED = " tag is not allowed in any field";
	private static final String MSG_ALL_FIELDS_EMPTY = "Please fill at least one field.";
	private static final String ERROR_BOX_TITLE = "Input Text Warning!";
	private static final String MSG_PROJECT_CHAR_ERROR = "The character \"<space>\" is not allowed in Project Tag.";
	private static final String NO_DATE_LOAD_TEXT = "";
	private static final String EMPTY_FIELD_LOAD_TEXT = "";
	private static final String  BUTTON_NAME = "Save and Exit";
	private static final String  DESCRIPTION_LABEL = "Description: ";
	private static final String  TITLE_LABEL = "Title: ";
	private static final String  LOCATION_LABEL = "Location: ";
	private static final String  PROJECT_LABEL = "Project (no spaces allowed): ";
	private static final String  START_TIME_LABEL = "Start Time: ";
	private static final String  END_TIME_LABEL = "End Time: ";
	
	
	public static Task executeAdd(Task givenTask) {
		isAdd = true;
		executeAddEdit(givenTask);
		return task;
	}

	private static void executeAddEdit(Task givenTask) {
		// TODO Auto-generated method stub
		isSearch = false;
		duplicateTask(givenTask);
		createFrameWithAptTitle();
		addNonViewAllDesign();
	}

	private static void createFrameWithAptTitle() {
		if(isAdd){
			createFrame("Add Task");
		}else{
			createFrame("Edit Task number " + task.id);
		}
	}

	
	public static Task executeEdit(Task givenTask) {
		isAdd = false;
		executeAddEdit(givenTask);
		return task;
	}

	public static Task executeSearch() {
		isSearch = true;
		isAdd = false;
		task = new Task();
		createFrame("Search for Tasks ");
		addNonViewAllDesign();
		return task;
	}

	
	private static void duplicateTask(Task givenTask) {
		// TODO Auto-generated method stub
		task = new Task();
		task.id = givenTask.id;
		task.title = givenTask.title;
		task.description = givenTask.description;
		task.startTime = givenTask.startTime;
		task.endTime = givenTask.endTime;
		task.project = givenTask.project;
		task.place = givenTask.place;
		task.isDone = givenTask.isDone;
	}

	private static void addNonViewAllDesign() {
		// TODO Auto-generated method stub

		configureTaskIDPanel();
		configureNamePanel();
		configureDatePanel();
		configureLocationTagPanel();
		configureDescriptionPanel();
		configureButtonPanel();
		if (isSearch == false) {
			initializeFieldWithGivenTask();
		}
		createDoneOption();
		configureBasicPanel();
	}

	private static void showErrorDialogBox(String errorMessage) {
		// TODO Auto-generated method stub
		JOptionPane.showMessageDialog(jd, errorMessage, ERROR_BOX_TITLE,
				JOptionPane.WARNING_MESSAGE);
	}

	private static void initializeFieldWithGivenTask() {
		// TODO Auto-generated method stub
		initializeNonDateFields();
		initializeDateFields();
	}

	private static void initializeDateFields() {
		
		initializeStartTime();
		initializeEndTime();
	}

	private static void initializeEndTime() {
		try {
			endTimeField.setText(sdf1.format(task.endTime));
		} catch (Exception e) {
			try {
				endTimeField.setText(sdf2.format(task.endTime));
			} catch (Exception e2) {
				endTimeField.setText(NO_DATE_LOAD_TEXT);
			}
		}
	}

	private static void initializeStartTime() {
		try {
			startTimeField.setText(sdf1.format(task.startTime));
		} catch (Exception e) {
			try {
				startTimeField.setText(sdf2.format(task.startTime));
			} catch (Exception e2) {
				startTimeField.setText(NO_DATE_LOAD_TEXT);
			}
		}
	}

	private static void initializeNonDateFields() {
		taskIDLabel.setText(taskIDLabel.getText() + task.id);
		nameField.setText(task.title);
		descriptionText.setText(task.description);
		tagField.setText(task.project);
		locationField.setText(task.place);
	}

	private static void configureButtonPanel() {
		buttonPanel = new JPanel();
		saveButton = new JButton(BUTTON_NAME);
		saveButton.setBackground(Color.GREEN);
		addButtonListener();
		buttonPanel.add(saveButton);
	}

	private static void addButtonListener() {
		saveButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				checkNonDateFields();
				checkDateFields();
				closePopUpIfOkay();
			}

			private void closePopUpIfOkay() {
				if (isSyntaxError == false) {
					retrieveDetails();
					isComplete = true;
					jd.dispose();
				}
			}

			private void checkDateFields() {
				checkDateFormats();
				try {
					checkForReversedDates();
				} catch (InvalidInputException e1) {
					isSyntaxError = true;
					showErrorDialogBox(WRONG_DATE_FORMAT);
				}
			}

			private void checkNonDateFields() {
				checkForInvalidChar();
				if (!isSearch) {
					checkForEmptyTitle();
				} else {
					checkForAllEmpty();
				}
			}

		});
	}

	protected static void checkForAllEmpty() {
		boolean emptyCheckCondition = nameField.getText().trim().equals(EMPTY_FIELD_LOAD_TEXT)
				&& startTimeField.getText().trim().equals(NO_DATE_LOAD_TEXT)
				&& endTimeField.getText().trim().equals(NO_DATE_LOAD_TEXT)
				&& locationField.getText().trim().equals(EMPTY_FIELD_LOAD_TEXT)
				&& tagField.getText().trim().equals(EMPTY_FIELD_LOAD_TEXT);
		
		if (emptyCheckCondition) {
			isSyntaxError = true;
			showErrorDialogBox(MSG_ALL_FIELDS_EMPTY);
		}
	}

	protected static void checkDateFormats() {
		// TODO Auto-generated method stub
		boolean isStartTimeError = false;
		
		isStartTimeError = checkStartTime(isStartTimeError);
		if (!isStartTimeError) {
			checkEndTime();
		}
	}

	private static void checkEndTime() {
		Date endTimeFormat;
		if (!endTimeField.getText().trim().equals(NO_DATE_LOAD_TEXT)) {
			try {
				endTimeFormat = DateTimeParser.parse(
						endTimeField.getText(), false);
			} catch (Exception e) {
				isSyntaxError = true;
				showErrorDialogBox(WRONG_ET_FORMAT);
			}
		}
	}

	private static boolean checkStartTime(boolean isStartTimeError) {
		Date startTimeFormat;
		if (!startTimeField.getText().trim().equals(NO_DATE_LOAD_TEXT)) {
			try {
				startTimeFormat = DateTimeParser.parse(
						startTimeField.getText(), true);
			} catch (Exception e) {
				isStartTimeError = true;
				isSyntaxError = true;
				showErrorDialogBox(WRONG_ST_FORMAT);
			}
		}
		return isStartTimeError;
	}

	protected static void checkForEmptyTitle() {
		// TODO Auto-generated method stub
		String enteredTitle = nameField.getText();

		if (enteredTitle.trim().equals(EMPTY_FIELD_LOAD_TEXT)) {
			isSyntaxError = true;
			showErrorDialogBox(MSG_NO_TITLE_ERROR);
		}
	}

	private static void checkForReversedDates() throws InvalidInputException {
		// TODO Auto-generated method stub

		Date startTime, endTime;
		startTime = getStartTimeDate();
		endTime = getEndTimeDate();
		checkForReversal(startTime, endTime);
	}

	private static void checkForReversal(Date startTime, Date endTime) {
		if (!(startTime == Task.EMPTY_TIME || endTime == Task.EMPTY_TIME)) {
			if (startTime.after(endTime)) {
				isSyntaxError = true;
				showErrorDialogBox(dateOrderError);
			}
		}
	}

	private static Date getEndTimeDate() throws InvalidInputException {
		Date endTime;
		String endTimeString = endTimeField.getText();
		if (endTimeString.trim().equals(NO_DATE_LOAD_TEXT)) {
			endTimeString = Task.EMPTY_STRING;
			endTime = Task.EMPTY_TIME;
		} else {
			endTime = DateTimeParser.parseTime(endTimeString, false);
		}
		return endTime;
	}

	private static Date getStartTimeDate() throws InvalidInputException {
		Date startTime;
		String startTimeString = startTimeField.getText();
		if (startTimeString.trim().equals(NO_DATE_LOAD_TEXT)) {
			startTimeString = Task.EMPTY_STRING;
			startTime = Task.EMPTY_TIME;
		} else {
			startTime = DateTimeParser.parseTime(startTimeString, true);
		}
		return startTime;
	}


	private static void configureDescriptionPanel() {
		initializeDescriptionComponents();
		configureDescriptionTextArea();
		addDescriptionComponents();
	}

	private static void addDescriptionComponents() {
		descriptionPanel.add(BorderLayout.WEST, descriptionLabel);
		descriptionPanel.add(BorderLayout.CENTER, descriptionText);
	}

	private static void initializeDescriptionComponents() {
		descriptionPanel = new JPanel(new BorderLayout());
		descriptionLabel = new JLabel(DESCRIPTION_LABEL);
		descriptionText = new JTextArea();
	}

	private static void configureDescriptionTextArea() {
		descriptionText.setLineWrap(true);
		descriptionText.setWrapStyleWord(true);
		descriptionText.setSize(10, 1);
		descriptionText.setSize(descriptionText.getPreferredSize());
	}

	private static void configureLocationTagPanel() {
		initializeLocTagComponents();
		addLocTagComponents();
	}

	private static void addLocTagComponents() {
		locationTagPanel.add(locationLabel);
		locationTagPanel.add(locationField);
		locationTagPanel.add(tagLabel);
		locationTagPanel.add(tagField);
	}

	private static void initializeLocTagComponents() {
		locationTagPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		locationLabel = new JLabel(LOCATION_LABEL);
		locationField = new JTextField(20);

		tagLabel = new JLabel(PROJECT_LABEL);
		tagField = new JTextField(8);
	}

	private static void configureDatePanel() {
		initializeDateComponents();
		addDateComponents();
	}

	private static void addDateComponents() {
		timePanel.add(startTimeLabel);
		timePanel.add(startTimeField);
		timePanel.add(endTimeLabel);
		timePanel.add(endTimeField);
	}

	private static void initializeDateComponents() {
		timePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		startTimeLabel = new JLabel(START_TIME_LABEL);
		endTimeLabel = new JLabel(END_TIME_LABEL);
		startTimeField = new JTextField(12);
		endTimeField = new JTextField(12);
	}

	private static void configureNamePanel() {
		initializeTitleComponents();
		addTitleComponents();
	}

	private static void addTitleComponents() {
		namePanel.add(nameLabel);
		namePanel.add(nameField);
	}

	private static void initializeTitleComponents() {
		namePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		nameLabel = new JLabel(TITLE_LABEL);
		nameField = new JTextField(50);
	}

	private static void configureTaskIDPanel() {
		taskIDPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		String taskID = "Task ID:  ";
		taskIDLabel = new JLabel(taskID);
		taskIDPanel.add(taskIDLabel);
	}

	private static void configureBasicPanel() {
		// TODO Auto-generated method stub
		basicPanel = new JPanel();
		basicPanel.setLayout(new BoxLayout(basicPanel, BoxLayout.Y_AXIS));
		addPanels();
		launchGUI();
	}

	private static void launchGUI() {
		// TODO Auto-generated method stub
		jd.add(basicPanel);
		makeFrameVisible();
	}

	private static void addPanels() {
		// TODO Auto-generated method stub
		if(!isSearch){
			basicPanel.add(taskIDPanel);
		}
		basicPanel.add(namePanel);
		basicPanel.add(timePanel);
		basicPanel.add(locationTagPanel);
		basicPanel.add(descriptionPanel);
		if (!isSearch) {
			basicPanel.add(doneCheckBox);
		}
		basicPanel.add(buttonPanel);

	}

	private static void retrieveDetails() {
		// TODO Auto-generated method stub
		retrieveTitle();
		retrievePlace();
		retrieveStartTime();
		retrieveEndTime();
		retrieveProject();
		retrieveDescription();
		retrieveDone();
		
	}

	
	private static void retrieveDone() {
		if (!isSearch) {
			task.isDone = doneCheckBox.isSelected();
		}
	}

	private static void retrieveDescription() {
		task.description = descriptionText.getText().trim();
		if (task.description.equals(EMPTY_FIELD_LOAD_TEXT)) {
			task.description = Task.EMPTY_STRING; 
		}
		
	}

	private static void retrieveProject() {
		task.project = tagField.getText().trim();
		if (task.project.equals(EMPTY_FIELD_LOAD_TEXT)) {
			task.project = Task.EMPTY_STRING;
		}
	}

	private static void retrieveEndTime() {
		try {
			task.endTime = DateTimeParser.parse(endTimeField.getText(), false);
		} catch (Exception e) {
			task.endTime = Task.EMPTY_TIME;
		}
	}

	private static void retrieveStartTime() {
		try {
			task.startTime = DateTimeParser.parse(startTimeField.getText(),
					true);
		} catch (Exception e) {
			task.startTime = Task.EMPTY_TIME;
		}
	}

	private static void retrievePlace() {
		task.place = locationField.getText().trim();
		if (task.place.equals(EMPTY_FIELD_LOAD_TEXT)) {
			task.place = Task.EMPTY_STRING;
		}
	}

	private static void retrieveTitle() {
		task.title = nameField.getText().trim();
		if (task.title.equals(EMPTY_FIELD_LOAD_TEXT)) {
			task.title = Task.EMPTY_STRING;
		}
	}

	private static void configureTaskTextFieldsList() {
		// TODO Auto-generated method stub
		taskTextFields = new ArrayList<String>();
		taskTextFields.add(task.title);
		taskTextFields.add(task.description);
		taskTextFields.add(task.place);
		taskTextFields.add(task.project);
	}

	private static void checkForInvalidChar() {
		// TODO Auto-generated method stub
		configureTextFieldsList();
		isSyntaxError = false;
		isTagErrorFound = false;
		
		for (JTextField selectedComponent : textFieldsList) {
			String text = selectedComponent.getText();
			testProjectSpaceChar(selectedComponent, text);
			testFieldTags(selectedComponent, text);
		}
		if (!isSyntaxError) {
			testDescription();
		}

	}

	private static void testDescription() {
		// TODO Auto-generated method stub
		String[] textArray = descriptionText.getText().split(" ");
		
		checkAllWordsForTags(textArray);
		checkForProjectTag(textArray);
	}

	private static void checkForProjectTag(String[] textArray) {
		String tag = PROJECT_TAG;
		for (int i = 0; i < textArray.length; i++) {
			if (textArray[i].startsWith(tag)) {
				isSyntaxError = true;
				showErrorDialogBox(tag + MSG_TAG_NOT_ALLOWED);
				break;
			}
		}
	}

	private static void checkAllWordsForTags(String[] textArray) {
		for (String tags : taskUITags) {
			for (int i = 0; i < textArray.length; i++) {
				if (textArray[i].equalsIgnoreCase(tags)) {
					isSyntaxError = true;
					showErrorDialogBox(tags + MSG_TAG_NOT_ALLOWED);
					break;
				}
			}
			if (isSyntaxError) {
				break;
			}
		}
	}

	private static void testFieldTags(JTextField selectedComponent, String text) {
		// TODO Auto-generated method stub
		String[] textArray = text.split(" ");
		if (selectedComponent != tagField) {
			checkAllWordsForTags(textArray);
		}
		checkForProjectTag(textArray);

	}

	private static void configureTextFieldsList() {
		textFieldsList = new ArrayList<JTextField>();
		textFieldsList.add(nameField);
		textFieldsList.add(startTimeField);
		textFieldsList.add(endTimeField);
		textFieldsList.add(tagField);
		textFieldsList.add(locationField);

	}

	private static void testProjectSpaceChar(JTextComponent selectedComponent,
			String text) {
		if (selectedComponent == tagField) {
			if (text.contains(" ")) {
				isSyntaxError = true;
				showErrorDialogBox(MSG_PROJECT_CHAR_ERROR);
			}
		}
	}


	public static void createDoneOption() {
		doneCheckBox = new JCheckBox();
		doneCheckBox.setText("Task Done");
		doneCheckBox.setSelected(task.isDone);
	}

	public static void createFrame(String title) {
		jd = new JDialog(MainUi.mainFrame, true);
		jd.setTitle(title);
		addWindowListener();
		jd.setSize(800, 400);
	}

	public static void makeFrameVisible() {
		jd.setVisible(true);
	}

	private static void addWindowListener() {
		jd.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				task = null;
				jd.dispose();
			}

		});
	}

}
